/**
 * 函数之间兼容性比较复杂,需要考虑
 *      1.参数个数
 *      2.参数类型
 *      3.返回值类型
 * 
 * 
 */

// 1.参数个数,参数多的兼容参数少的(参数少的可以赋值给参数多的)
//js函数中用不到的参数可省略
type F1 = (a:number) => void

type F2 = (a:number,b:number) => void

let f1: F1 = function add (a) {}
let f2: F2 = function add2 (a,b) {}

f2 = f1

// 解释
//1.参数少的可以赋值给参数多的,所以,f1可以赋值给f2
//2.数组forEach方法的第一个参数是回调函数,该实例中类型为(value:string,index:number,array:string[] => void)
//3.在js中省略用不到的函数参数实际上是很常见的,这样的使用方式,促成了ts中函数类型直接的兼容性
//4.并且因为回调函数是有类型的,所以,ts会自动推导出参数item,index,array的类型






//2.参数类型,相同位置的参数类型要相同(原始类型)或兼容(对象类型)


type F11 = (a:number) => void
type F22 = (b:number) => void //报错 
// type F22 = (a:string) => void //报错 

let f11:F11 = function add1 (a) {}
let f22:F22 = function add2 (b) {}

f11 = f22


interface Point3 {
    x:number
    y:number
}

interface Point4 {
    x:number
    y:number
    z:number
}

type F3 = (p: Point3) => void
type F4 = (p: Point4) => void

let f3:F3 = function add3(p) {}

let f4:F4 = function add3(p) {}

f4 = f3
// f3=f4 //错误

//解释
//1.注意,此处与前面讲的接口兼容性冲突
//2.技巧,将对象拆开,把每个属性看做一个个参数,则参数少的f3可以赋值给参数多的f4




//3.返回值类型,只关注返回值类型本身即可


type F5 = () => string
type F6 = () => string

let f5:F5 = function add5(){return 'tom'}

let f6:F6 = function add5(){return 'tom'}

f5 = f6



type F7 = () => {name:string}
type F8 = () => {name:string;age:number}

let f7:F7 = function add7 () {return {name:'tom'}}

let f8:F8 = function add8 () {return {name:'tom',age:19}}

f7 = f8


//解释
//1.如果返回值类型是原始类型,此时两个类型要相同,比如 f5,f6
//2.如果返回值类型是对象类型,此时成员多的可以赋值给成员少的,比如,f7,f8


